package com.hk.core.redis.annotations;

import com.hk.commons.exceptions.RequiredLockException;

import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;

/**
 * redis 锁使用注解的方式
 *
 * @author Kevin
 * @see com.hk.core.redis.locks.RedisLock
 * @see com.hk.core.redis.aspect.RedisLockInterceptor
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RedisLock {

    /**
     * <pre>
     * 锁的 Key，支持 SPEL 表达式
     * SPEL格式如:
     *      #参数名，如方法为method(int value) ,则可以使用 #value 获取
     *      也可以使用计算公式: 如 "1+1" -> 结果为2
     *      方法参数也可以使用对象，如 method(int value, Object obj) ，如果想以obj的属性作为key,可以写成 #obj.属性名。
     *      如果方法参数有数组，如 method(int[]arr) ,可以使用 #arr[0] 获取第几个元素作为key
     *      如果方法参数有map，如 method(int[]arr,Map<String,Object> map) ,可以使用 #map[key] 获取map指定key的值作为锁的key
     *      如果方法参数有list，如 method(List<String> list) ,可以使用 #list[0] 获取list指定的索引作为锁的key
     * </pre>
     */
    String key();

    /**
     * 锁的过期时间，单位为秒,默认20 秒
     */
    long expireSeconds() default 20;

    /**
     * 是否对 key 续期
     */
    boolean renewal() default false;

    /**
     * 如果大于0，配合{@link  #tryLockUnit()} 在指定时间内获取到锁，则加锁，获取不到不加锁
     * 如果等于0，尝试获取锁，并立即返回结果
     * 如果小于等于0，阻塞获取锁，直到获取到锁
     */
    long tryLockTime() default -1;

    /**
     * 获取锁过程是否允许中断，如果允许中断，当被其它                                                                                                                                                                                                                              x           线程打断时，会抛出 {@link InterruptedException}
     */
    boolean interrupt() default false;

    /**
     * 是否必需获取到锁，如果设置为true，且没有获取到锁时，会抛出 {@link  RequiredLockException}
     * 如果设置为false,没有获取到锁时，也会执行目标方法
     */
    boolean requiredLock() default true;

    /**
     * 尝试获取锁的过期时间单位
     */
    TimeUnit tryLockUnit() default TimeUnit.MILLISECONDS;

}
